#include "def.h"
#include "option.h"
#include "xn5106x.h"
#include "drv_sys.h"
#include "drv_uart.h"
#include "drv_int.h"
#include "os_api.h"
#include "mw_nram.h"
#include "sys_glb.h"
#include "app_afn.h"
#include "drv_tmr.h"

#define DRV_UART2_FLG			1
#define DRV_UART2_PARITY_CHK	1
#define ISR_VECTOR_FLG			0


#if DRV_UART2_FLG

#define UART_BAUD2_1200		10000		// Clock number
#define UART_BAUD2_2400		5000
#define UART_BAUD2_4800		2500
#define UART_BAUD2_9600		1250
#define UART_BAUD2_19200	625
#define UART_BAUD2_38400	312


#define DRV_U2CON_PARITY_NO		0x00
#define DRV_U2CON_PARITY_ODD	0x01
#define DRV_U2CON_PARITY_EVEN	0x02
#define DRV_U2CON_PARITY_MARK	0x03
#define DRV_U2CON_PARITY_SPACE	0x04

#define DRV_U2CON_STOP_ONE		0x00
#define DRV_U2CON_STOP_TWO		0x04

#if	ISR_VECTOR_FLG
#define DRV_UART2_TM_EINT		(98)	// EINT delay compensate (Unit clock)
#define DRV_UART2_TM_TMR0		(96)	// T4_0 delay compensate (Unit clock)
#define DRV_UART2_TM_TMR1		(51)	// T4_1 delay compensate (Unit clock)
#else
#define DRV_UART2_TM_EINT		(98+6)	// EINT delay compensate (Unit clock), +2T
#define DRV_UART2_TM_TMR0		(96+3)	// T4_0 delay compensate (Unit clock), +1T
#define DRV_UART2_TM_TMR1		(51+3)	// T4_1 delay compensate (Unit clock), +1T
#endif

#define DRV_UART2_SAMPLE_NUM_19200	3
#define DRV_UART2_SAMPLE_NUM_9600	5
#define DRV_UART2_SAMPLE_NUM_4800	13
#define DRV_UART2_SAMPLE_NUM_2400	21
#define DRV_UART2_SAMPLE_NUM_1200	21

#define SAMPLE_LEVEL(x)				(x/2+2)

#define DRV_UART2_TM_SAMPLE_T0		(72)  // Sample entry delay (Uint clock )
#define DRV_UART2_TM_SAMPLE_T1		(27)  	// Sample one loop delay (Uint clock )

#define SIM_RX_IO		P05				// P05
#define SIM_RX_INT_NUM	INT_NUM_EINT0	// EINT0 (P05)
#define SIM_RX_INT_BIT	BIT_EINT0		// EINT0 (P05)

#define DRV_UART2_DATA_LEN_PARITY	9

#define UART2_FIFO_LEN_MAX		128
typedef struct
{
	volatile U16 m_rU2TMR0;
	volatile U16 m_rU2TMR1;
	volatile U8 m_rU2CON;
	volatile U8 m_rU2SSR;
	volatile U8 m_rU2RBR;
	volatile U8 m_rU2RCNT;		// rU2RCNT= 0;		// With parity
	volatile U16 m_rU2RDATA;	// 8bit(data)+1bit(parity)
	volatile U8 m_rU2RXFLG;		// 0: Disable RX; Other: Enable RX
	volatile U8 m_rU2MOD;		// 0: Send; Other: Receive mode
	volatile U8 m_rU2Head;		// FIFO Header
	volatile U8 m_rU2Tail;		// FIFO Tail
	volatile U8 m_rU2Buff[UART2_FIFO_LEN_MAX];
	volatile U8 m_sample_num;
	volatile U8 m_sample_level;
	volatile U16 m_rU2TMR0_B;
	volatile U16 m_rU2TMR1_B;
}DRV_UART2_REG_T;

typedef struct
{
	U16 m_uart_baud;
	U16 m_uart2_baud;
	U8 m_sample_num;
	U8 m_sample_level;
}DRV_UART2_BAUD;

DRV_UART2_REG_T rUART2Base;

const U8 c_drv_uart2_tbl[16] = 
{
	0, 1, 1, 2, 
	1, 2, 2, 3,
	1, 2, 2, 3,
	2, 3, 3, 4
};

const DRV_UART2_BAUD c_drv_uart2_baud_tbl[] = 
{
	{ UART_BAUD_1200, UART_BAUD2_1200, DRV_UART2_SAMPLE_NUM_1200, SAMPLE_LEVEL(DRV_UART2_SAMPLE_NUM_1200)  },
	{ UART_BAUD_2400, UART_BAUD2_2400, DRV_UART2_SAMPLE_NUM_2400, SAMPLE_LEVEL(DRV_UART2_SAMPLE_NUM_2400) },
	{ UART_BAUD_4800, UART_BAUD2_4800, DRV_UART2_SAMPLE_NUM_4800, SAMPLE_LEVEL(DRV_UART2_SAMPLE_NUM_4800) },
	{ UART_BAUD_9600, UART_BAUD2_9600, DRV_UART2_SAMPLE_NUM_9600, SAMPLE_LEVEL(DRV_UART2_SAMPLE_NUM_9600) },
	{ UART_BAUD_19200, UART_BAUD2_19200, DRV_UART2_SAMPLE_NUM_19200, SAMPLE_LEVEL(DRV_UART2_SAMPLE_NUM_19200) },
};

#ifdef __ARMCC__
#pragma arm
#pragma O2
#pragma OTime
#endif

#ifdef __ICCARM__
#pragma type_attribute=__arm
#endif
/*
* Function Name:
*   drv_uart2_bit_sample
* Description:
*   drv_uart2 bit sample
* Parameters:
*   
* Returns:
*   :
* Author				Date 
*  Jerry				2011-9-27   
* Note:
*    
*/
U32 drv_uart2_bit_sample(void )
{
	U32 sample_idx = rUART2Base.m_sample_num;
	U32 low_cnt = 0;

	while ( sample_idx-- )
	{
		if ( 0 == (rP0&(0x01<<SIM_RX_IO)) )
		{
			low_cnt++;
		}
	}

	if ( low_cnt >= rUART2Base.m_sample_level )
	{
		return 0;
	}

	return 1;
}


/*
* Function Name:
*   drv_uart2_byte_proc
* Description:
*   drv_uart2 byte procedure
* Parameters:
*   U16 rec_word: 8bit(data)+1bit(parity)
* Returns:
*   :
* Author				Date 
*  Jerry				2011-9-27   
* Note:
*    
*/
void drv_uart2_byte_proc( U16 rec_word )
{
	// Check Parity
	DRV_UART2_REG_T *p_uart2_reg;
#if DRV_UART2_PARITY_CHK
	U8 high_num;
	U8 parity_type;
#endif
	BOOL err_flg = 0;
	U8 ssr;

	rT4CON = 0x00;		// Stop timer4
	p_uart2_reg = &rUART2Base;
#if DRV_UART2_PARITY_CHK

	parity_type = (p_uart2_reg->m_rU2CON&0x07);
	#if 0
	if ( DRV_U2CON_PARITY_NO != parity_type )	
	{
		high_num = c_drv_uart2_tbl[rec_word&0x0F]+c_drv_uart2_tbl[(rec_word>>4)&0x0F];
		err_flg = ((rec_word&BIT8)>>8)^(high_num&0x01);		// Even parity
		err_flg = (DRV_U2CON_PARITY_ODD == parity_type)?(!err_flg):err_flg;
	}
	#else
	if (( DRV_U2CON_PARITY_ODD == parity_type )	||( DRV_U2CON_PARITY_EVEN == parity_type ))
	{
		high_num = c_drv_uart2_tbl[rec_word&0x0F]+c_drv_uart2_tbl[(rec_word>>4)&0x0F];
		err_flg = ((rec_word&BIT8)>>8)^(high_num&0x01);		// Even parity
		err_flg = (DRV_U2CON_PARITY_ODD == parity_type)?(!err_flg):err_flg;
	}
	else
	{
		err_flg = ((rec_word&BIT8)>>8)^(0x01);				// Mark parity
		err_flg = (DRV_U2CON_PARITY_SPACE == parity_type)?(!err_flg):err_flg;
	}
	#endif

#endif

	ssr = p_uart2_reg->m_rU2SSR;
	ssr |= (err_flg<<1);		// Parity flag
	// Push to FIFO
	{
		register isOS_S32 flag;
		register isOS_U8 tail;
		register isOS_U8 head;

		tail = p_uart2_reg->m_rU2Tail;
		head = p_uart2_reg->m_rU2Head;
	
		flag = ((tail == 0 && head == UART2_FIFO_LEN_MAX - 1)
				|| head == tail-1);
		if ( flag )
		{
			ssr |= (USSR_ERR_OVERRUN|USSR_RX);
		}
		else
		{
			p_uart2_reg->m_rU2Buff[head++] = (U8)rec_word;
			head = (head>=UART2_FIFO_LEN_MAX)?0:head;
			p_uart2_reg->m_rU2Head = head;
			ssr |= USSR_RX;
		}
	}

	p_uart2_reg->m_rU2SSR = ssr;
	//rUART2Base.m_rU2RDATA = 0;
	rINTPEND = (~SIM_RX_INT_BIT);

	//if ( rUART2Base.m_rU2RXFLG )
	{
		//  Active UART2 sim-interrupt
		rINTMASK |= (BIT_BT|SIM_RX_INT_BIT);
	}
}

/*
* Function Name:
*   drv_uart2_int_clr
* Description:
*   UART2 interrupt clear
* Parameters:
* Returns:
*   :
* Author				Date 
*  Jerry				2011-9-27   
* Note:
*    
*/
void drv_uart2_int_clr( void )
{
	volatile U32 *p_reg;
	register isOS_U8 tail;
	register isOS_U8 head;
	U8 *p_ssr;
	
	tail = rUART2Base.m_rU2Tail;
	head = rUART2Base.m_rU2Head;

	p_reg = &rINTMASK;
	p_ssr = (U8 *)&rUART2Base.m_rU2SSR;
	rSYSCON &= (~BIT8);			// Disable global interrupt
	if ( tail == head )
	{	// FIFO is empty
		*p_reg &= (~BIT_BT);		// Disable BT timer
		*p_ssr = 0;
	}
	rSYSCON |= (BIT8);			// Enable global interrupt
}

/*
* Function Name:
*   drv_uart2_fifo_pop
* Description:
*   UART2 fifo pop
* Parameters:
* Returns:
*   U8:
* Author				Date 
*  Jerry				2011-9-27   
* Note:
*    
*/
U8 drv_uart2_fifo_pop( void )
{
	register isOS_U8 tail;
	register isOS_U8 head;
	U8 rec_byte;
	
	tail = rUART2Base.m_rU2Tail;
	head = rUART2Base.m_rU2Head;

	if (tail != head)
	{
		rec_byte = rUART2Base.m_rU2Buff[tail++];
		tail = (tail>=UART2_FIFO_LEN_MAX)?0:tail;
		rUART2Base.m_rU2Tail = tail;
	}
	else
	{
		rec_byte = 0;
	}
	return rec_byte;
}

/*
* Function Name:
*   drv_uart2_fifo_empty
* Description:
*   UART2 FIFO is empty
* Parameters:
* Returns:
*   U8:
* Author				Date 
*  Jerry				2011-9-27   
* Note:
*    
*/
U8 drv_uart2_fifo_empty( void )
{
	register isOS_U8 tail;
	register isOS_U8 head;
	
	tail = rUART2Base.m_rU2Tail;
	head = rUART2Base.m_rU2Head;

	return (tail==head);
}

/*
* Function Name:
*   drv_uart2_ssr_get
* Description:
*   UART2 SSR Get
* Parameters:
* Returns:
*   U8:
* Author				Date 
*  Jerry				2012-5-24   
* Note:
*    
*/
U8 drv_uart2_ssr_get( void )
{
	U8 by_tmp;
	by_tmp = rUART2Base.m_rU2SSR;
	return by_tmp;
}

/*
* Function Name:
*   drv_uart2_ssr_clr
* Description:
*   UART2 SSR clear
* Parameters:
* Returns:
*   :
* Author				Date 
*  Jerry				2012-5-24   
* Note:
*    
*/
void drv_uart2_ssr_clr( void )
{
	U32 cpu_sr;

	isOS_ENTER_CRITICAL(cpu_sr);
	rSYSCON &= (~BIT8);
	rUART2Base.m_rU2SSR = 0x00;
	rSYSCON |= (BIT8);
	isOS_EXIT_CRITICAL(cpu_sr);
}

#ifdef __ARMCC__
#pragma O1
#pragma thumb
#endif

#ifdef __ICCARM__
#pragma type_attribute=__thumb
#endif


/*
* Function Name:
*   drv_uart2_hw_rx_ena
* Description:
*   UART2 RX Enable/Disable
* Parameters:
*   BOOL rx_flg: TRUE--Enable; FALSE--Disable
* Returns:
*   :
* Author				Date 
*  Jerry				2011-9-27   
* Note:
*    
*/
void drv_uart2_hw_rx_ena( BOOL rx_flg )
{
	rINTPEND = (~(SIM_RX_INT_BIT|INT_NUM_T4MC));
	drv_int_ena( SIM_RX_INT_NUM, rx_flg );
	drv_int_ena( INT_NUM_T4MC, rx_flg );
	rUART2Base.m_rU2RXFLG = rx_flg;
}

/*
* Function Name:
*   drv_uart2_hw_init
* Description:
*   Sim-Uart init
* Parameters:
*   U16 baud: baud2 should use UART_BAUD2_xxxx
*   S32 offset: sample position offset( >0: pre-standard, <0: post-standard ), unit (us)
*   U8 ctrl_reg: Control register value
* Returns:
*   BOOL:
* Author				Date 
*  Jerry				2011-9-21   
* Note:
*    
*/
BOOL drv_uart2_hw_init( U16 baud, S32 offset, U8 ctrl_reg )
{
	U16 baud2 = 0;
	S32 i;
	for ( i = 0; i<sizeof(c_drv_uart2_baud_tbl)/sizeof(DRV_UART2_BAUD); i++ )
	{
		if ( c_drv_uart2_baud_tbl[i].m_uart_baud == baud )
		{
			baud2 = c_drv_uart2_baud_tbl[i].m_uart2_baud;
			break;
		}
	}

	if ( 0 == baud2 )
	{	// Baud-rate is not available
		return FALSE;
	}


	rUART2Base.m_rU2CON = ctrl_reg;
	rUART2Base.m_rU2SSR = 0x00;
	rUART2Base.m_sample_num = c_drv_uart2_baud_tbl[i].m_sample_num;
	rUART2Base.m_sample_level = c_drv_uart2_baud_tbl[i].m_sample_level;
	rUART2Base.m_rU2TMR1 = baud2-1;
	rUART2Base.m_rU2TMR1_B = rUART2Base.m_rU2TMR1;
	offset = offset*(EXTCLK_FREQ/1000000);	// us --> Clock
	rUART2Base.m_rU2TMR0 = baud2+(baud2>>1)-DRV_UART2_TM_EINT-DRV_UART2_TM_TMR0 \
				-DRV_UART2_TM_TMR1+offset-1 \
				-DRV_UART2_TM_SAMPLE_T0-DRV_UART2_TM_SAMPLE_T1*(rUART2Base.m_sample_num/2);	
	rUART2Base.m_rU2TMR0_B = rUART2Base.m_rU2TMR0;
	
	rUART2Base.m_rU2MOD = 1;		// Receive mode
	rUART2Base.m_rU2RXFLG = 1;		// Enable receive
	rUART2Base.m_rU2Head = 0;
	rUART2Base.m_rU2Tail = 0;

	// UART2 IRQ interrupt ISR. Use BT interrupt number
	drv_int_ena( INT_NUM_BT, FALSE );

	// Enable EINT1 interrupt
	//rP1FUN_SEL |= BIT6;
	drv_sys_port0_setmod( SIM_RX_IO, IO_INPUT );
	drv_sys_port0_setfunc( SIM_RX_IO, IO_FUNC_SP );
	drv_sys_port0_setpur( SIM_RX_IO, IO_PUR_EN );
	drv_int_mode_set( SIM_RX_INT_NUM, 1);
	rINTPEND = (~SIM_RX_INT_BIT);
	drv_int_ena( SIM_RX_INT_NUM, TRUE );

	// Enable EINT1 interrupt
	rT4PRE = 0x00;		// No pre-devide
	drv_tmr_ena( TMR4_UART2, FALSE );
	drv_int_mode_set( INT_NUM_T4MC, 1);
	rINTPEND = (~BIT_T4MC);
    drv_int_ena( INT_NUM_T4MC, TRUE );

	return TRUE;
}

/*
* Function Name:
*   drv_uart2_check
* Description:
*   UART2 check
* Parameters:
* Returns:
*   :
* Author				Date 
*  Jerry				2011-9-28   
* Note:
*    
*/
void drv_uart2_check( void )
{
	U32 cpu_sr;

	isOS_ENTER_CRITICAL( cpu_sr );
	rSYSCON &= (~BIT8);
	if ( rUART2Base.m_rU2RXFLG \
		 &&( 0==(rT4CON&0x80) && 0==(rINTMASK&SIM_RX_INT_BIT)) )
	{	// UART2 RX enable, T4 is disabled and RX_INT is disabled. should reset system.
		cpu_sr = cpu_sr;
		while( 1 );		// Waitint for reset
	}
	rSYSCON |= (BIT8);
	isOS_EXIT_CRITICAL( cpu_sr );

	if ( !(drv_int_stat(INT_NUM_T4MC)) )
	{
		// Enable EINT1 interrupt
		rT4PRE = 0x00;		// No pre-devide
		drv_tmr_ena( TMR4_UART2, FALSE );
		drv_int_mode_set( INT_NUM_T4MC, 1);
		rINTPEND = (~BIT_T4MC);
		drv_int_ena( INT_NUM_T4MC, TRUE );		
	}

	if ( rP0FUN_SEL&(0x01<<SIM_RX_IO) )
	{	// IO mode, should update
		drv_sys_port0_setmod( SIM_RX_IO, IO_INPUT );
		drv_sys_port0_setfunc( SIM_RX_IO, IO_FUNC_SP );
		drv_sys_port0_setpur( SIM_RX_IO, IO_PUR_EN );
		drv_int_mode_set( SIM_RX_INT_NUM, 1);
		rINTPEND = (~SIM_RX_INT_BIT);
		drv_int_ena( SIM_RX_INT_NUM, TRUE );
	}
	
	if ( rUART2Base.m_rU2TMR1_B != rUART2Base.m_rU2TMR1 \
		 ||rUART2Base.m_rU2TMR0_B != rUART2Base.m_rU2TMR0 )
	{
		isOS_ENTER_CRITICAL( cpu_sr );
		cpu_sr = cpu_sr;
		while( 1 );		// Waitint for reset
	}

}


#endif	// end DRV_UART2_FLG

